xquery version "1.0";

module namespace t = "http://fgeorges.org/ns/oauth/tools";

declare function t:current-timestamp()
   as xs:integer
{
   let $epoch    := xs:dateTime('1970-01-01T00:00:00+00:00')
   let $duration := current-dateTime() - $epoch
   let $one-sec  := xs:dayTimeDuration('PT1S')
   return
      xs:integer($duration div $one-sec)
};

declare function t:uri-query-string($uri as xs:string)
   as xs:string?
{
   if ( matches($uri, '\?') ) then
      replace($uri, '^[^?]+\?(.+)$', '$1', 's')
   else
      ()
};

(:~
 : Parse a value of type "application/x-www-form-urlencoded" into name/value pairs.
 :
 : Use to parse the result of requesting temporary credentials, as well as
 : parsing URL query strings.
 :)
declare function t:parse-form-urlencoded($value as xs:string)
   as element(params)
{
   <params> {
      for $t in tokenize($value, '&amp;')[.]
      return
         <param name="{ t:decode-from-uri(substring-before($t, '=')) }"> {
            t:decode-from-uri(substring-after($t, '='))
         }
         </param>
   }
   </params>
};

declare function t:decode-from-uri($value as xs:string)
   as xs:string
{
   if ( contains($value, '%') ) then
      let $before := substring-before($value, '%')
      let $len    := string-length($before)
      let $code   := substring($value, $len + 2, 2)
      let $after  := substring($value, $len + 4)
      return
         concat(
             $before,
             t:decode-escaped-char($code),
             t:decode-from-uri($after))
   else
      $value
};

declare function t:decode-escaped-char($value as xs:string)
   as xs:string
{
   if ( string-length($value) eq 2 ) then
      codepoints-to-string(
         t:hexa-char-value(substring($value, 1, 1)) * 16
         + t:hexa-char-value(substring($value, 2, 1)))
   else
      error((), concat('Bad escaping: ''%', $value, ''''))
};

declare function t:hexa-char-value($value as xs:string)
   as xs:integer
{
   let $map :=
         <digits>
            <digit char="0">0</digit>
            <digit char="1">1</digit>
            <digit char="2">2</digit>
            <digit char="3">3</digit>
            <digit char="4">4</digit>
            <digit char="5">5</digit>
            <digit char="6">6</digit>
            <digit char="7">7</digit>
            <digit char="8">8</digit>
            <digit char="9">9</digit>
            <digit char="a">10</digit>
            <digit char="A">10</digit>
            <digit char="b">11</digit>
            <digit char="B">11</digit>
            <digit char="c">12</digit>
            <digit char="C">12</digit>
            <digit char="d">13</digit>
            <digit char="D">13</digit>
            <digit char="e">14</digit>
            <digit char="E">14</digit>
            <digit char="f">15</digit>
            <digit char="F">15</digit>
         </digits>
   let $integer := $map/digit[@char eq $value]/xs:integer(.)
   return
      if ( empty($integer) ) then
         error((), concat('Wrong hexa digit: ''', $value, ''''))
      else
         $integer
};
